/*
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>

#define MAX 20100

struct edge {
    int veradj;
    int cost;
    struct edge* link;
};

struct vertex {
    int vername; // 这个字段在您的代码中未使用，可以根据需要保留或删除
    struct edge* adjacent;
};

struct value {
    int o;
    int p;
    int q;
};

struct vertex vert[MAX];
struct value val[MAX];

void prepare(int n) {
    for (int i = 0; i < n; i++) {
        struct edge* head = (struct edge*)malloc(sizeof(struct edge));
        head->veradj = -1; // 哨兵节点，不存储有效相邻顶点信息
        head->link = NULL;
        vert[i].adjacent = head;
    }
}

void build(int a, int b, int c) {
    struct edge* newedge = (struct edge*)malloc(sizeof(struct edge));
    newedge->veradj = b;
    newedge->cost = c;
    newedge->link = NULL;
    struct edge* head = vert[a].adjacent;
    newedge->link = head->link; // 插入到链表头部（或根据需要插入到其他位置）
    head->link = newedge;
    // 注意：这里我们没有更新 vert[a].adjacent，它始终指向头节点
}

void output(int n) {
    for (int i = 0; i < n; i++) {
        struct edge* ptr = vert[i].adjacent; // 跳过头节点
        if(vert[i].adjacent->link==NULL) continue;
		printf("%d:", i);
        ptr = vert[i].adjacent->link; 
        while (ptr != NULL) {
            printf("(%d,%d,%d) ", i, ptr->veradj, ptr->cost);
            ptr = ptr->link;
        }
        printf("\n");
    }
}

int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    prepare(n);
    for (int u = 0; u < m; u++) {
        scanf("%d%d%d", &val[u].o, &val[u].p, &val[u].q);
    }
    for (int u = 0; u < m; u++) {
        build(val[u].o, val[u].p, val[u].q);
    }
    output(n);
    // 注意：这里没有释放内存，实际应用中应该添加释放内存的代码
    return 0;
}

*/


#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>
#include <stdlib.h>
#include <limits.h> // 用于 INT_MAX

#define MAX 20100

struct edge {
    int veradj;
    int cost;
    edge* link;
};

struct vertex {
    int vername; // 如果不使用，可以移除
    edge* adjacent;
};

struct value {
    int o;
    int p;
    int q;
};

struct vertex vert[MAX];
struct value val[MAX];

void prepare(int n) {
    for (int i = 0; i < n; i++) {
        struct edge* head = (struct edge*)malloc(sizeof(struct edge));
        head->cost = INT_MAX; // 初始化为一个很大的值，表示没有边
        head->link = NULL;
        vert[i].adjacent = head;
    }
}

void build(int a, int b, int c) {
    struct edge* newedge = (struct edge*)malloc(sizeof(struct edge));
    newedge->veradj = b;
    newedge->cost = c;
    newedge->link = vert[a].adjacent->link; // 插入到头节点的后面
    vert[a].adjacent->link = newedge;
}

void print_min_adjacent_edge(int n) {
    for (int i = 0; i < n; i++) {
        struct edge* current = vert[i].adjacent->link; // 跳过头节点
        struct edge* min_edge = NULL;
        int min_cost = INT_MAX;

        while (current != NULL) {
            if (current->cost < min_cost) {
                min_cost = current->cost;
                min_edge = current;
            }
            current = current->link;
        }

        // 如果找到了一个真正的边（成本不是 INT_MAX）
        if (min_edge != NULL) {
            printf("(%d,%d,%d)\n", i, min_edge->veradj, min_edge->cost);
        } else {
            printf("(%d,no adjacent edges with positive cost)\n", i);
        }
    }
}

int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    for (int u = 0; u < m; u++) {
        scanf("%d%d%d", &val[u].o, &val[u].p, &val[u].q);
    }
    prepare(n);
    for (int u = 0; u < m; u++) {
        build(val[u].o, val[u].p, val[u].q);
    }
    print_min_adjacent_edge(n);
    return 0;
}